package com.jzo2o.customer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.customer.dto.response.AddressBookResDTO;
import com.jzo2o.api.publics.MapApi;
import com.jzo2o.api.publics.dto.response.LocationResDTO;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.customer.mapper.AddressBookMapper;
import com.jzo2o.customer.model.domain.AddressBook;
import com.jzo2o.customer.model.dto.request.AddressBookPageQueryReqDTO;
import com.jzo2o.customer.model.dto.request.AddressBookUpsertReqDTO;
import com.jzo2o.customer.service.IAddressBookService;
import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.mysql.utils.PageUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * <p>
 * 地址薄 服务实现类
 * </p>
 *
 * @author itcast
 * @since 2023-07-06
 */
@Service
public class AddressBookServiceImpl extends ServiceImpl<AddressBookMapper, AddressBook> implements IAddressBookService {

    @Resource
    private AddressBookMapper addressBookMapper;

    @Resource
    private MapApi mapApi;

    /**
     * 根据用户ID和地址城市查询地址薄
     *
     * @param userId 用户ID
     * @param city   地址城市
     * @return 地址薄列表
     */
    @Override
    public List<AddressBookResDTO> getByUserIdAndCity(Long userId, String city) {

        List<AddressBook> addressBooks = lambdaQuery()
                .eq(AddressBook::getUserId, userId)
                .eq(AddressBook::getCity, city)
                .list();
        if (CollUtils.isEmpty(addressBooks)) {
            return new ArrayList<>();
        }
        return BeanUtils.copyToList(addressBooks, AddressBookResDTO.class);
    }


    /**
     * 分页查询地址薄
     *
     * @param dto 分页查询参数，包含查询条件和分页信息。
     * @return 分页结果，包含当前页的数据列表和分页信息。
     */
    @Override
    public PageResult<AddressBookResDTO> pageQuery(AddressBookPageQueryReqDTO dto) {

        // 解析分页查询参数，生成Page对象
        Page<AddressBook> page = PageUtils.parsePageQuery(dto, AddressBook.class);

        // 构造查询Wrapper，设置查询条件（当前用户ID）
        LambdaQueryWrapper<AddressBook> queryWrapper =
                Wrappers.<AddressBook>lambdaQuery().eq(AddressBook::getUserId, UserContext.currentUserId());

        // 根据查询条件和分页参数执行数据库查询
        Page<AddressBook> serveTypePage = addressBookMapper.selectPage(page, queryWrapper);

        // 将查询结果转换为前端需要的分页结果格式
        return PageUtils.toPage(serveTypePage, AddressBookResDTO.class);
    }


    /**
     * 新增地址薄
     *
     * @param dto 新增参数
     */
    @Override
    public void addAddressBook(AddressBookUpsertReqDTO dto) {

        // 1.获取当前用户id
        Long userId = UserContext.currentUserId();
        // 2.如果新增地址未默认，则取消默认地址 -> 修改需要使用到，进行方法抽取
        if (dto.getIsDefault().equals(0)) {
            canceDefault(userId);
        }
        // 2.1 bean转化
        AddressBook addressBook = BeanUtils.toBean(dto, AddressBook.class);
        addressBook.setUserId(userId);

        // 3.组装(拼接)详细地址
        String completeAddress = dto.getProvince() + dto.getCity() + dto.getCounty() + dto.getAddress();

        // 4.如果请求体中没有经纬度，需要调用第三方api根据详细地址获取经纬度
        if (ObjectUtils.isEmpty(dto.getLocation())) {
            // 4.1 远程请求高德获取经纬度
            LocationResDTO locationDto = mapApi.getLocationByAddress(completeAddress);
            // 4.2经纬度(字符串格式：经度,纬度),经度在前，纬度在后
            String location = locationDto.getLocation();
            dto.setLocation(location);
        }

        if (StringUtils.isNotBlank(dto.getLocation())) {
            // 经度
            addressBook.setLon(NumberUtil.parseDouble(dto.getLocation().split(",")[0]));
            // 纬度
            addressBook.setLat(NumberUtil.parseDouble(dto.getLocation().split(",")[1]));

        }
        addressBookMapper.insert(addressBook);
    }

    /**
     * 编辑地址薄
     *
     * @param id  地址薄id
     * @param dto 编辑参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editAddressBook(Long id, AddressBookUpsertReqDTO dto) {

        // 1.获取当前用户id
        Long userId = UserContext.currentUserId();
        // 2.如果新增地址未默认，则取消默认地址 -> 修改需要使用到，进行方法抽取
        if (dto.getIsDefault().equals(1)) {
            canceDefault(userId);
        }
        // 2.1 bean转化
        AddressBook addressBook = BeanUtils.toBean(dto, AddressBook.class);
        addressBook.setId(id);

        // 3.调用第三方，根据地址获取经纬度
        String completeAddress = dto.getProvince() + dto.getCity() + dto.getCounty() + dto.getAddress();
        // 4.远程请求高德获取经纬度
        LocationResDTO locationResDTO = mapApi.getLocationByAddress(completeAddress);
        // 经纬度（字符串格式：经度，维度），经度在前，纬度在后
        String location = locationResDTO.getLocation();

        if (StringUtils.isNotBlank(location)) {
            // 经度
            addressBook.setLon(NumberUtil.parseDouble(location.split(",")[0]));
            // 纬度
            addressBook.setLat(NumberUtil.parseDouble(location.split(",")[1]));
        }
        addressBookMapper.updateById(addressBook);
    }

    /**
     * 取消默认地址的设置。
     * 该方法将指定用户的默认地址设置为非默认（即设置isDefault字段为0）
     *
     * @param userId 用户ID，用于指定需要取消默认地址的用户。
     */
    private void canceDefault(Long userId) {
        // 构造更新条件，设置指定用户的所有地址的isDefault字段为0
        LambdaUpdateWrapper<AddressBook> wrapper = Wrappers.<AddressBook>lambdaUpdate()
                .eq(AddressBook::getUserId, userId)
                .set(AddressBook::getIsDefault, 0);
        // 执行更新操作
        super.update(wrapper);
    }

    /**
     * 根据id获取地址薄
     *
     * @param id 地址薄id
     * @return 地址薄
     */
    @Override
    public AddressBookResDTO getAddressById(Long id) {

        LambdaQueryWrapper<AddressBook> wrapper =
                Wrappers.<AddressBook>lambdaQuery().eq(AddressBook::getId, id);

        return BeanUtils.toBean(addressBookMapper.selectOne(wrapper), AddressBookResDTO.class);
    }


    /**
     * 批量删除地址薄。此方法通过提供的地址薄id列表，逐个将地址薄标记为删除状态。
     * 注意：这里并非物理删除，而是通过设置isDeleted字段为1来表示该条记录已被删除。
     *
     * @param ids 地址薄id列表，类型为List<Long>。这是要被删除的地址薄的id集合。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAddressBook(List<Long> ids) {

        Iterator<Long> iterator = ids.iterator();

        // 遍历id列表，对每个id进行删除操作
        while (iterator.hasNext()) {
            Long id = iterator.next();
            // 构造更新语句，将指定id的地址薄的isDeleted字段设置为1
            LambdaUpdateWrapper<AddressBook> wrapper = Wrappers.<AddressBook>lambdaUpdate()
                    .eq(AddressBook::getId, id)
                    .set(AddressBook::getIsDeleted, 1);
            super.update(wrapper);
            // 查询更新后的地址薄记录，以确认删除操作是否成功
            AddressBook addressBook = addressBookMapper.selectById(id);
            // 如果查询不到记录，表示删除操作成功，将该id从列表中移除
            if (addressBook == null) {
                iterator.remove();
            }
        }
    }

    /**
     * 设置默认地址
     *
     * @param id   地址薄id
     * @param flag 是否默认
     */
    @Override
    public void isDefault(Long id, Short flag) {
        // 获取当前用户的id
        Long userId = UserContext.currentUserId();
        if (flag ==1) {
            //如果设默认地址，先把其他地址取消默认
            canceDefault(userId);
        }
        LambdaUpdateWrapper<AddressBook> wrapper = Wrappers.<AddressBook>lambdaUpdate()
                .eq(AddressBook::getId, id)
                .set(AddressBook::getIsDefault, flag);

        super.update(wrapper);
    }


    /**
     * 获取默认地址
     *
     * @return all
     */
    @Override
    public AddressBookResDTO defaultAddress() {
        LambdaQueryWrapper<AddressBook> queryWrapper =
                Wrappers.<AddressBook>lambdaQuery()
                        // 查询当前用户id
                .eq(AddressBook::getUserId, UserContext.currentUserId())
                        // 查询默认地址
                .eq(AddressBook::getIsDefault, 1);
        AddressBook addressBook = addressBookMapper.selectOne(queryWrapper);
        return BeanUtil.toBean(addressBook, AddressBookResDTO.class);
    }





}

